package com.example.xcService.pojo.tool;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.naming.pojo.healthcheck.impl.Http;
import com.alibaba.nacos.common.utils.MapUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.pojo.response.CardInfo;
import com.example.xcService.pojo.channels.ChannelResult;
import com.example.pojo.request.OrderReverse;
import com.example.pojo.request.VpOffsiteSkuInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.util.DigestUtils;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
public class RefundTool {

    /*合合扫描王退单*/
    public static ChannelResult DoAgentOrderHHSMW(Map<String, String> apiConfig, Map<String, String> data) {
       try {
           String appId = apiConfig.get("AppId");
           String cooperateNo = apiConfig.get("CooperateNo");
           String key = apiConfig.get("AppKey");
           String refoundUrl = apiConfig.get("RefoundUrl");
           String channelOrderCode = data.get("ChannelOrderCode");
           long timestamp = System.currentTimeMillis();

           HashMap<String, String> RefoundParams = new HashMap<>();
           RefoundParams.put("app_id",appId);
           RefoundParams.put("cooperate_no",cooperateNo);
           RefoundParams.put("timestamp",String.valueOf(timestamp));
           RefoundParams.put("order_id",channelOrderCode);
           String sign = generateSign(RefoundParams, key);
           RefoundParams.put("sign",sign);

           String resStr = HttpTool.sendPost(refoundUrl, RefoundParams);
           JSONObject resObj = JSONObject.parseObject(resStr);
           String code = resObj.getString("code");
           String msg = resObj.getString("msg");
           if (code.equals("0")) {
               return ChannelResult.success("操作成功");
           }
           return ChannelResult.FAILED("操作失败:"+msg);
       }catch (Exception e){
           return ChannelResult.FAILED("操作失败:合合退款接口错误");
       }
    }

    public static String generateSign(Map<String, String> params,String appKey) throws Exception {
        // 使用TreeMap对参数按照ASCII码表顺序排序
        Map<String, String> sortedParams = new TreeMap<>(params);
        // 拼接参数串
        StringBuilder queryStringBuilder = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
            queryStringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        queryStringBuilder.append("secret=").append(appKey);
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest = md.digest(queryStringBuilder.toString().getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }


    /*业务类型(1-qq会员 2-qq超级会员 3-普通黄钻 4-豪华黄钻 5-大会员)*/
    //QQ会员-七天无理由
    public static ChannelResult DoAgentOrderQQHY(Map<String,String> apiConfig, Map<String,String> data){
        String appId = apiConfig.get("RefoundAppId");
        String orderId = String.valueOf(data.get("ChannelOrderCode"));
        String accountVal = String.valueOf(data.get("AccountVal"));
        String supProductId = String.valueOf(data.get("SUPProductId"));
        String aesSecretKey = apiConfig.get("AESSecretKey");
        String iv = apiConfig.get("IV");
        String refundUrl = apiConfig.get("RefundUrl");

        try {
            HashMap<String, String> hashMap = new HashMap<>();
            String[] split = supProductId.split("/");
            if (split.length>=3){
                hashMap.put("day",split[2]);
                hashMap.put("biz",split[1]);
            }else {
                return ChannelResult.FAILED("操作失败:无理由退款产品id配置错误");
            }
            hashMap.put("appid",appId);
            hashMap.put("order_id",orderId);
            hashMap.put("uin",accountVal);
            hashMap.put("reason","other");

            String sortedAndFormatted = new TreeMap<>(hashMap).entrySet().stream()
                    .map(entry -> entry.getKey() + "=" + entry.getValue())
                    .collect(Collectors.joining("&"));
            // 使用AES/CBC/PKCS5PADDING进行加密，密钥和IV偏移量根据实际情况进行设置
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
            SecretKeySpec secretKeySpec = new SecretKeySpec(aesSecretKey.getBytes(StandardCharsets.UTF_8), "AES");
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            byte[] encryptedBytes = cipher.doFinal(sortedAndFormatted.getBytes(StandardCharsets.UTF_8));
            String encryptedString = java.util.Base64.getEncoder().encodeToString(encryptedBytes);
            hashMap.put("sign",encryptedString);

            String resStr = HttpTool.sendGet(refundUrl, hashMap);
            JSONObject parseObject = JSONObject.parseObject(resStr);
            String ret = parseObject.getString("ret");
            String msg = parseObject.getString("msg");
            if (ret.equals("0")){
                return ChannelResult.success("操作成功");
            }
            return ChannelResult.FAILED("操作失败:"+msg);
        }catch (Exception e) {
            return ChannelResult.FAILED("操作失败:QQ会员退款接口错误");
        }
    }


    //美团单车-删券
    public static ChannelResult DoAgentOrderMTDC(Map<String,String> apiConfig, Map<String,String> order){
       try {
           String accountVal = String.valueOf(order.get("AccountVal"));
           String apiSource = apiConfig.get("ApiSource");

           HashMap<String, String> delCardParams = new HashMap<>();

           if(Pattern.matches("^1[3456789]\\d{9}$", accountVal) == true){
               delCardParams.put("mobileNo",accountVal);
           }else {
               delCardParams.put("mtUserId",accountVal);
           }
           delCardParams.put("performanceSource",apiSource);
           delCardParams.put("channelTransToken",String.valueOf(order.get("ChannelOrderCode")));
           delCardParams.put("activityId",String.valueOf(order.get("SUPProductId")));
           String key = apiConfig.get("SecretKey");
           String sign = sign(delCardParams, key);
           delCardParams.put("sign",sign);
           String delCardUrl = apiConfig.get("DelCardUrl");

           String respStr = HttpTool.HttpPost(delCardUrl, delCardParams);
           JSONObject respObj = JSONObject.parseObject(respStr);
           String code = respObj.getString("code");
           String message = respObj.getString("message");
           if (code.equals("0")){
               return ChannelResult.success("操作成功");
           }
           return ChannelResult.FAILED("操作失败:"+message);
       }catch (Exception e) {
           return ChannelResult.FAILED("操作失败:退订接口异常");
       }


    }

    public static String sign(Map<String, String> params, String key) throws
            UnsupportedEncodingException {
        if (MapUtils.isEmpty(params) || StringUtils.isBlank(key)) {
            return StringUtils.EMPTY;
        }
        TreeMap<String, String> fields = new TreeMap<>();
        for (Map.Entry<String, String> en : params.entrySet()) {
            if ("sign".equals(en.getKey())) {
                continue;
            }
            fields.put(en.getKey(), en.getValue());
        }
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : fields.entrySet()) {
            if (StringUtils.isBlank(entry.getValue()) ||
                    "null".equals(entry.getValue())) {
                continue;
            }
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        String before = sb.append(key).toString();
        String after = org.apache.commons.codec.digest.DigestUtils.md5Hex(before.getBytes("utf8")).toUpperCase();

        log.debug("md5 sign before : {}, after : {}", before, after);
        return after;

    }


    //美团到店-废券
    public static ChannelResult DoAgentOrderMTQ(Map<String,String> apiConfig, Map<String,String> order){

        try {
            Map<String,String> dataParams=new HashMap<>();
            dataParams.put("order_no",order.get("ChannelOrderCode"));
            dataParams.put("mobile",order.get("AccountVal"));
            String appSecret = apiConfig.get("SecretKey");
            String abolishUrl = apiConfig.get("AbolishUrl");

            String result = dataParams.entrySet().stream()
                    .sorted(Map.Entry.comparingByKey())
                    .map(entry -> entry.getKey() + entry.getValue())
                    .collect(Collectors.joining());
            result += appSecret;
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] array = md.digest(result.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte item : array) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100), 1, 3);
            }
            String sign = sb.toString().toLowerCase();

            dataParams.put("sign",sign);

            String responseContent = HttpTool.sendPost(abolishUrl, dataParams);
            JSONObject retobj = JSONObject.parseObject(responseContent);
            String status=retobj.getString("code");
            String message=retobj.getString("message");
            if("200".equals(status)){
                return ChannelResult.success("操作成功");
            }else {
                return ChannelResult.FAILED("操作失败:"+message);
            }
        }catch (Exception e) {
            return ChannelResult.FAILED("操作失败:退订接口异常");
        }
    }


    public static ChannelResult DoAgentOrderELM(Map<String,String> apiConfig, Map<String,String> order){

        Map<String,String> dataParams=new HashMap<>();
        DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String timeMillis=dtf.format(LocalDateTime.now());
        dataParams.put("timestamp",timeMillis);
        dataParams.put("outerOrderId",order.get("ChannelOrderCode"));
        dataParams.put("phone",order.get("AccountVal"));
        String appSecret = apiConfig.get("AppSecret");
        String refundUrl = apiConfig.get("RefundUrl");
        String signStr="";
        signStr="outerOrderId="+order.get("ChannelOrderCode")+"&phone="+order.get("AccountVal")+"&timestamp="+timeMillis+appSecret;


        String sign = DigestUtils.md5DigestAsHex(signStr.getBytes());
        dataParams.put("sign",sign);





        String url=refundUrl;
        String responseContent = HttpTool.sendPost(url, dataParams);
        JSONObject retobj = JSONObject.parseObject(responseContent);
        String status=retobj.getString("code");
        String error_code=retobj.getString("errorMsg");
        if("200".equals(status)){
            return ChannelResult.success("操作成功");
        }else {
            return ChannelResult.FAILED("操作失败:"+error_code);
        }
    }

    public static ChannelResult DoAgentOrderKG(Map<String,String> apiConfig, Map<String,String> order){

        String user_type = "1";

        if (Pattern.matches("^[1-9][0-9]{4,10}$",order.get("AccountVal")) == true)
        {
            user_type = "2";
        }

        Map<String,String> dataParams=new HashMap<>();
        dataParams.put("main_key",apiConfig.get("USERID"));
        dataParams.put("out_trade_no",order.get("ChannelOrderCode"));
        dataParams.put("user_type",user_type);
        dataParams.put("user",order.get("AccountVal"));





        String[] productCodes=order.get("SUPProductId").split(",");
        if (productCodes.length<2){
            return ChannelResult.FAILED("操作失败:"+"产品编码错误");
        }


        String productType=productCodes[0];
        String SUPProductId=productCodes[1];
        dataParams.put("product_type",productType);
        dataParams.put("days",SUPProductId);
        dataParams.put("sign_type","sha1");
        dataParams.put("timestamp",String.valueOf(System.currentTimeMillis()));
        String sign= KGTool.generateSign(dataParams,apiConfig.get("SecretKey"));
        dataParams.put("sign",sign);
        String url="https://openvip.kugou.com/direct_recharge/v1/recover_order";
        String responseContent = HttpTool.sendPost(url, dataParams);
        JSONObject retobj = JSONObject.parseObject(responseContent);
        String status=retobj.getString("status");
        String error_code=retobj.getString("error_code");
        if("1".equals(status) && "0".equals(error_code)){
            return ChannelResult.success("操作成功");
        }else {
            return ChannelResult.FAILED("操作失败:"+error_code);
        }
    }

    public static  ChannelResult  DoAgentOrderMT(Map<String,String> apiConfig,Map<String,String> order) throws Exception{



        Map<String,String> headers=new HashMap<>();
        String curTime=String.valueOf(System.currentTimeMillis());
        headers.put("S-Ca-App", apiConfig.get("S-Ca-App"));
        headers.put("S-Ca-Timestamp",curTime);
        List<String> signHeaderPrefixList=new ArrayList<>();
        signHeaderPrefixList.add("S-Ca-App");
        signHeaderPrefixList.add("S-Ca-Timestamp");

        OrderReverse orderInfo=new OrderReverse();
        orderInfo.setServiceProviderCode(String.valueOf(apiConfig.get("USERID")));
        orderInfo.setSaleChannel(Integer.valueOf(String.valueOf(apiConfig.get("saleChannel"))));
        orderInfo.setPhone(order.get("AccountVal"));
        orderInfo.setServiceProviderOrderId(order.get("ChannelOrderCode"));

        List<VpOffsiteSkuInfo> skus=new ArrayList<>();

        VpOffsiteSkuInfo vpOffsiteSkuInfo=new VpOffsiteSkuInfo();
        vpOffsiteSkuInfo.setSkuViewId(order.get("SUPProductId"));
        vpOffsiteSkuInfo.setServiceProviderSkuOrderId(order.get("ChannelOrderCode"));
        skus.add(vpOffsiteSkuInfo);
        orderInfo.setSkuList(skus);

        String body= JSONObject.toJSONString(orderInfo);
        String contentMD5 = new String(org.apache.commons.codec.binary.Base64.encodeBase64(stringToMD5(body.getBytes("UTF-8"))));
        String Headers=buildHeaders(headers,signHeaderPrefixList);

        String stringToSign= "POST" + "\n" + contentMD5 + "\n" + Headers + "/partner/coupon_package/order_reverse";
        String HeaderStr = "S-Ca-App,S-Ca-Timestamp";
        Mac hmacSha256 = Mac.getInstance("HmacSHA256");
        byte[] keyBytes = apiConfig.get("SecretKey").getBytes("UTF-8");
        hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, "HmacSHA256"));

        String sign=new  String(org.apache.commons.codec.binary.Base64.encodeBase64(
                hmacSha256.doFinal(stringToSign
                        .getBytes("UTF-8"))),
                "UTF-8");

        headers.put("S-Ca-Signature",sign);
        headers.put("S-Ca-Signature-Headers",HeaderStr);
        headers.put("Content-MD5",contentMD5);

        String url="http://i.waimai.meituan.com/partner/coupon_package/order_reverse";



        String res= sendPost(url,JSONObject.toJSONString(orderInfo),headers);
        JSONObject retobj = JSONObject.parseObject(res);
        String status=retobj.getString("code");
        if("0".equals(status)){
            JSONArray skuList=retobj.getJSONArray("skuList");
            String code=skuList.getObject(0,JSONObject.class).getString("status");
            if ("1".equals(code) || "2".equals(code) ){
                return ChannelResult.success("操作成功");
            }else if ("5".equals(status)){
                return ChannelResult.FAILED("操作失败:"+status);
            }else {
                return ChannelResult.FAILED("操作失败:"+code);
            }

        }
        else if ("201".equals(status)){
            return ChannelResult.FAILED("操作失败:"+status);
        }
        else {
            return ChannelResult.FAILED("操作失败:"+status);
        }
    }


    public static  ChannelResult  DoAgentOrderSY(Map<String,String> apiConfig,Map<String,String> order) throws Exception{


        JSONObject apiCfg= JSONObject.parseObject(JSONObject.toJSONString(apiConfig));
        JSONObject dataConfig= JSONObject.parseObject(JSONObject.toJSONString(order));

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("jsonObject", apiCfg.getString("USERID"));
        jsonObject.put("projectId", dataConfig.getString("SUPProductId"));
        jsonObject.put("phone", dataConfig.getString("AccountVal"));
        jsonObject.put("outerOrderCode", dataConfig.getString("ChannelOrderCode"));
        String unencryptedContent = JSONObject.toJSONString(jsonObject);

        String encryptedContent = segmentedEncryptByRsaPublicKeyStr(apiCfg.getString("SecretKey"), unencryptedContent);





        Map dataParams = new LinkedHashMap<String, String>();
        dataParams.put("channel",  apiCfg.getString("USERID"));
        dataParams.put("encryptedContent", encryptedContent);



        String url=apiCfg.getString("RefundURL");

        String responseContent = HttpTool.sendPost(url, dataParams);
        JSONObject retobj = JSONObject.parseObject(responseContent);

        String code = retobj.getString("resultCode");
        String msg = retobj.getString("resultMsg");
        Boolean data=retobj.getBoolean("data");

        if (code.equals("0") && data) {
            return ChannelResult.success("充值成功");
        }
        else if (code.equals("100000")){
            return ChannelResult.FAILED("未知情况");
        }
        else {
            return ChannelResult.FAILED(code+","+msg);
        }
    }

    /**
     * 得到RSA公钥
     *
     * @param publicKeyStr 公钥字符串
     * @return publicKey 公钥
     * @author 付聪
     * @time 2023/6/1 15:48
     */
    public static PublicKey getRsaPublicKey(String publicKeyStr) {


        PublicKey publicKey = null;
        try {
            byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr.getBytes(StandardCharsets.UTF_8));
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        } catch (Exception e) {
            log.error("执行【getRsaPublicKey】方法，出现异常，异常信息如下：", e);
        }

        return publicKey;

    }

    public static String segmentedEncryptByRsaPublicKeyStr(String publicKeyStr, String unencryptedContent) {


        // 已加密的内容
        String encryptedContent = null;
        try {


            byte[] tempByteArray = unencryptedContent.getBytes("UTF-8");
            PublicKey publicKey = getRsaPublicKey(publicKeyStr);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            int inputLength = tempByteArray.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            int i = 0;
            byte[] cache;

            while (inputLength - offSet > 0) {
                if (inputLength - offSet > 245) {
                    cache = cipher.doFinal(tempByteArray, offSet, 245);
                } else {
                    cache = cipher.doFinal(tempByteArray, offSet, inputLength - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * 245;
            }

            byte[] encryptedContentByteArray = out.toByteArray();
            out.close();
            encryptedContent = Base64.getEncoder().encodeToString(encryptedContentByteArray);

        } catch (Exception e) {
            log.error("执行【segmentedEncryptByRsaPublicKeyStr】方法，出现异常，异常信息如下：", e);
        }

        return encryptedContent;

    }

    public static byte[] stringToMD5(byte[] plainText) throws Exception{
        byte[] secretBytes = null;
        StringBuilder md5code = new StringBuilder();
        try {
            secretBytes = MessageDigest.getInstance("md5").digest(
                    plainText);

        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return secretBytes;
    }

    private static String buildHeaders(Map<String, String> headers, List<String> signHeaderPrefixList) {
        StringBuilder sb = new StringBuilder();

        if (null != signHeaderPrefixList) {

            Collections.sort(signHeaderPrefixList);
            if (null != headers) {
                Map<String, String> sortMap = new TreeMap<String, String>();
                sortMap.putAll(headers);
                StringBuilder signHeadersStringBuilder = new StringBuilder();
                for (Map.Entry<String, String> header : sortMap.entrySet()) {
                    sb.append(header.getKey());
                    sb.append(":");
                    sb.append(header.getValue());
                    sb.append("\n");
                    if (0 < signHeadersStringBuilder.length()) {
                        signHeadersStringBuilder.append(",");
                    }
                    signHeadersStringBuilder.append(header.getKey());
                }
                headers.put("S-Ca-Signature-Headers", signHeadersStringBuilder.toString());
            }
        }

        return sb.toString();
    }

    public static String sendPost(String url, String param,Map<String,String> header) {
        String result = "";
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();

        // 创建Post请求
        HttpPost httpPost = new HttpPost(url);
        String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36";
        httpPost.setHeader("User-Agent",userAgent);

        // 响应模型
        CloseableHttpResponse response = null;
        try {
            // 设置ContentType(注:如果只是传普通参数的话,ContentType不一定非要用application/json)
            httpPost.setHeader("Content-Type", "application/json;charset=utf8");
            httpPost.setHeader("S-Ca-App","offsite_jianuo_online_app");
            httpPost.setHeader("S-Ca-Timestamp",header.get("S-Ca-Timestamp"));
            httpPost.setHeader("S-Ca-Signature",header.get("S-Ca-Signature"));
            httpPost.setHeader("S-Ca-Signature-Headers",header.get("S-Ca-Signature-Headers"));
            httpPost.setHeader("Content-MD5",header.get("Content-MD5"));
            httpPost.setEntity(new StringEntity(param));
            log.info("httpPost请求："+url+"?"+param);
            // 由客户端执行(发送)Post请求
            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();

            System.out.println("响应状态为:" + response.getStatusLine());
            if (responseEntity != null) {
                result= EntityUtils.toString(responseEntity);
                log.info("httpPost请求返回："+JSONObject.toJSONString(result));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return  result;
    }

}
